package io.gitee.loulan_yxq.owner.mybatisPlus.base;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.gitee.loulan_yxq.owner.core.exception.InvalidParameterException;
import io.gitee.loulan_yxq.owner.core.map.MapTool;
import io.gitee.loulan_yxq.owner.core.tool.ObjectTool;
import io.gitee.loulan_yxq.owner.core.tool.StrTool;
import io.gitee.loulan_yxq.owner.mybatisPlus.enums.QueryPageEnum;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

/*********************************************************
 ** 分页条件查询
 ** <br>
 ** 平时我们进行分页查询都是将PageCurrent和PageSize传输进来，然后再处理，这个类可以直接接受各种参数包括分页条件
 ** {
 **   "pageCurrent": 5,
 **   "pageSize": 30
 ** }
 ** Date: Created in 2021/12/3  10:19
 ** @author loulan
 ** @version 0.0.0
 *********************************************************/
public class QueryPageMap<T> extends LinkedHashMap<String, Object> {

    private Page<T> page;

    /**
     * 构造器，构造一个指定初始容量和加载因子的实例，{@link Page}对象需要再构造器中创建好
     *
     * @param initialCapacity 初始容量
     * @param loadFactor      加载因子
     * @author :loulan
     */
    public QueryPageMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        this.page = newPage();
    }

    /**
     * 构造器，构造一个指定初始容量，但是默认加载因子的实例，{@link Page}对象需要再构造器中创建好
     *
     * @param initialCapacity 初始容量
     * @author :loulan
     */
    public QueryPageMap(int initialCapacity) {
        super(initialCapacity);
        this.page = newPage();
    }

    /**
     * 构造器，构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的实例，{@link Page}对象需要再构造器中创建好
     *
     * @author :loulan
     */
    public QueryPageMap() {
        this.page = newPage();
    }

    /**
     * 构造器，构造一个指定包含一个Map实例的实例，{@link Page}对象需要再构造器中创建好
     *
     * @param m {@link Map}集合对象实例
     * @author :loulan
     */
    public QueryPageMap(Map<? extends String, ?> m) {
        super(m);
        this.page = newPage();
        this.setPageData(m);
    }

    /**
     * 构造器，构造一个指定初始容量和加载因子以及排序模式的实例，{@link Page}对象需要再构造器中创建好
     *
     * @param initialCapacity 初始容量
     * @param loadFactor      加载因子
     * @param accessOrder     排序模式
     * @author :loulan
     */
    public QueryPageMap(int initialCapacity, float loadFactor, boolean accessOrder) {
        super(initialCapacity, loadFactor, accessOrder);
        this.page = newPage();
    }

    /**
     * 创建一个{@link Page}对象
     *
     * @return {@link Page}对象
     * @author :loulan
     */
    private Page<T> newPage() {
        return new Page<>();
    }

    /**
     * 传入集合数据，然后设置分页对象的数据
     *
     * @param m Map集合
     * @author :loulan
     */
    private void setPageData(Map<? extends String, ?> m) {
        // 判断这个m集合里面是否已经有了page需要的pageCurrent和pageSize
        if (MapTool.isNotEmpty(m)) {
            // 向将数据转换为字符串
            if (m.containsKey(QueryPageEnum.PAGE_CURRENT.getCode())) {
                String pageCurrentStr = String.valueOf(m.get(QueryPageEnum.PAGE_CURRENT.getCode()));
                // 判断这个字符串不为空并且时数字
                if (StrTool.isNotEmpty(pageCurrentStr) && pageCurrentStr.matches("\\d+")) {
                    this.setCurrent(Long.parseLong(pageCurrentStr));
                    this.remove(QueryPageEnum.PAGE_CURRENT.getCode());
                } else {
                    throw new InvalidParameterException("【" + QueryPageEnum.PAGE_CURRENT.getCode() + "】参数异常。");
                }
            }

            if (m.containsKey(QueryPageEnum.PAGE_SIZE.getCode())) {
                String pageSizeStr = String.valueOf(m.get(QueryPageEnum.PAGE_SIZE.getCode()));

                if (StrTool.isNotEmpty(pageSizeStr) && pageSizeStr.matches("\\d+")) {
                    this.setSize(Long.parseLong(pageSizeStr));
                    this.remove(QueryPageEnum.PAGE_SIZE.getCode());
                } else {
                    throw new InvalidParameterException("【" + QueryPageEnum.PAGE_SIZE.getCode() + "】参数异常。");
                }
            }


        }
    }

    /**
     * 传入指定的key和value判断并写入page
     *
     * @param key   键
     * @param value 值
     * @return Optional容器
     * @author :loulan
     */
    private Optional setPageData(String key, Object value) {
        if (QueryPageEnum.PAGE_CURRENT.getCode().equals(key) || QueryPageEnum.PAGE_SIZE.getCode().equals(key)) {
            // 向将数据转换为字符串
            String pageValue = String.valueOf(value);
            if (StrTool.isNotEmpty(pageValue) && pageValue.matches("\\d+")) {
                if (QueryPageEnum.PAGE_CURRENT.getCode().equals(key)) {
                    this.setCurrent(Long.parseLong(pageValue));
                } else {
                    this.setSize(Long.parseLong(pageValue));
                }
            } else {
                throw new InvalidParameterException("【" + QueryPageEnum.PAGE_CURRENT.getCode() + "】或【" + QueryPageEnum.PAGE_SIZE.getCode() + "】参数异常。");
            }

            return Optional.ofNullable(value);
        } else {
            return Optional.empty();
        }
    }

    /**
     * 获取page对象
     *
     * @return 当前参数值
     * @author :loulan
     */
    public Page<T> getPage() {
        return this.page;
    }

    /**
     * 设置page对象
     *
     * @param page 分页参数对象
     * @author :loulan
     */
    public void setPage(Page<T> page) {
        this.page = page;
    }

    /**
     * 设置分页对象的当前页
     *
     * @param current 当前页的页码
     * @author :loulan
     */
    public void setCurrent(long current) {
        if (ObjectTool.isNull(this.page)) {
            this.page = newPage();
        }
        this.page.setCurrent(current);
    }

    /**
     * 设置分页对象大小
     *
     * @param size 分页的大小
     * @author :loulan
     */
    public void setSize(long size) {
        if (ObjectTool.isNull(this.page)) {
            this.page = newPage();
        }
        this.page.setSize(size);
    }

    /**
     * 获取分页的当前页码
     *
     * @return 分页当前页码
     * @author :loulan
     */
    public long getCurrent() {
        if (ObjectTool.isNull(this.page)) {
            this.page = newPage();
        }
        return this.page.getCurrent();
    }

    /**
     * 获取分页的页大小
     *
     * @return 页大小
     * @author :loulan
     */
    public long getSize() {
        if (ObjectTool.isNull(this.page)) {
            this.page = newPage();
        }
        return this.page.getSize();
    }

    /**
     * 获取并删除原来的数据
     *
     * @param key 要获取的key
     * @return 当前key对应的值value
     * @author :loulan
     */
    public Object getAndRemove(String key) {
        return remove(key);
    }

    @Override
    public Object put(String key, Object value) {
        if (setPageData(key, value).isPresent()) {
            return value;
        } else {
            return super.put(key, value);
        }
    }

    @Override
    public void putAll(Map<? extends String, ?> m) {
        super.putAll(m);
        this.setPageData(m);
    }

    @Override
    public Object putIfAbsent(String key, Object value) {
        // 分页的参数时一直存在的，一旦遇到分页的参数那么就直接进入判断
        if (QueryPageEnum.PAGE_CURRENT.getCode().equals(key) || QueryPageEnum.PAGE_SIZE.getCode().equals(key)) {
            // 这个方法的原理时，如果参数存在就返回值，不存在写入数据返回null
            return value;
        }
        return super.putIfAbsent(key, value);
    }
}
